#pragma once


#include <QtWidgets/QWidget>

#include "QtNodeData.hpp"
#include "QtSerializable.hpp"
#include "QtStyle.hpp"
#include "Export.hpp"

namespace Qt
{
	enum class NodeValidationState
	{
		Valid,
		Warning,
		Error
	};

	class QtConnection;
	class StyleCollection;
	class QtNodePainterDelegate;

	class NODE_EDITOR_PUBLIC QtNodeDataModel
		: public QObject
		, public QtSerializable
	{
		Q_OBJECT

	public:

		QtNodeDataModel();

		virtual
			~QtNodeDataModel() = default;

		/// Caption is used in GUI
		virtual QString
			caption() const = 0;

		virtual QString
			nodeTips() const { return "nodeTips"; }

		virtual QString
			portTips(PortType, PortIndex) const { return "portTips"; }

		/// It is possible to hide caption in GUI
		virtual bool
			captionVisible() const { return true; }

		virtual bool
			hotkeyEnabled() const { return true; }

		virtual bool 
			hotKeyRenderChecked() const { return true; }

		virtual bool
			hotKeyAutoSyncChecked() const { return true; }

		virtual bool
			hotKeySimChecked() const { return true; }

		/// Port caption is used in GUI to label individual ports
		virtual QString
			portCaption(PortType, PortIndex) const { return QString(); }

		/// It is possible to hide port caption in GUI
		virtual bool
			portCaptionVisible(PortType, PortIndex) const { return false; }

		virtual bool
			allowImported() const { return false; }

		virtual bool
			allowExported() const { return true; }

		/// Name makes this model unique
		virtual QString
			name() const = 0;

	public:

		QJsonObject
			save() const override;

	public:

		virtual
			unsigned int nPorts(PortType portType) const = 0;

		virtual
			NodeDataType dataType(PortType portType, PortIndex portIndex) const = 0;

	public:

		enum class ConnectionPolicy
		{
			One,
			Many,
		};

		virtual
			ConnectionPolicy
			portOutConnectionPolicy(PortIndex) const
		{
			return ConnectionPolicy::Many;
		}

		virtual
			ConnectionPolicy
			portInConnectionPolicy(PortIndex) const
		{
			return ConnectionPolicy::One;
		}

		NodeStyle const&
			nodeStyle() const;

		void
			setNodeStyle(NodeStyle const& style);

	public:

		/// Triggers the algorithm
		virtual	void setInData(std::shared_ptr<QtNodeData> nodeData, PortIndex port) = 0;

		virtual bool tryInData(PortIndex portIndex, std::shared_ptr<QtNodeData> nodeData) { return true; }

		virtual
			std::shared_ptr<QtNodeData>
			outData(PortIndex port) = 0;

		virtual
			QWidget *
			embeddedWidget() = 0;

		virtual
			bool
			resizable() const { return false; }

		virtual
			NodeValidationState
			validationState() const { return NodeValidationState::Valid; }

		virtual
			QString
			validationMessage() const { return QString(""); }

		virtual
			QtNodePainterDelegate* painterDelegate() const { return nullptr; }

	public Q_SLOTS:

		virtual void
			inputConnectionCreated(QtConnection const&)
		{
		}

		virtual void
			inputConnectionDeleted(QtConnection const&)
		{
		}

		virtual void
			outputConnectionCreated(QtConnection const&)
		{
		}

		virtual void
			outputConnectionDeleted(QtConnection const&)
		{
		}

	Q_SIGNALS:

		void
			dataUpdated(PortIndex index);

		void
			dataInvalidated(PortIndex index);

		void
			computingStarted();

		void
			computingFinished();

		void embeddedWidgetSizeUpdated();

	private:

		NodeStyle _nodeStyle;

		
	};
}
